﻿// <copyright file="WebExtensions.cs" company="Edge Extensions Project">
// Copyright (c) 2009 All Rights Reserved
// </copyright>
// <author>Kevin Nessland</author>
// <email>kevinnessland@gmail.com</email>
// <date>2009-07-08</date>
// <summary>Contains WebExtensions-related extension methods.</summary>
namespace Edge.Extensions.Web
{
    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Drawing;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web;
    using HtmlAgilityPack;

    /// <summary>
    /// Provides various web-related extensions.
    /// </summary>
    public static class WebExtensions
    {
        /// <summary>
        /// Downloads data from a url.
        /// </summary>
        /// <param name="url">Url to retrieve the data.</param>
        /// <returns>Byte array of data from the url.</returns>
        public static byte[] DownloadData(this string url)
        {
            byte[] downloadedData = new byte[0];

            try
            {
                WebRequest req = WebRequest.Create(url);
                WebResponse response = req.GetResponse();

                Stream stream = response.GetResponseStream();

                // Download in chunks
                byte[] buffer = new byte[1024];

                int dataLength = (int)response.ContentLength;

                // Download to memory
                MemoryStream memStream = new MemoryStream();

                while (true)
                {
                    int bytesRead = stream.Read(buffer, 0, buffer.Length);

                    if (bytesRead == 0)
                    {
                        break;
                    }
                    else
                    {
                        memStream.Write(buffer, 0, bytesRead);
                    }
                }

                downloadedData = memStream.ToArray();

                stream.Close();
                memStream.Close();
            }
            catch (Exception)
            {
                throw;
            }

            return downloadedData;
        }

        /// <summary>
        /// Downloads an image from a url.
        /// </summary>
        /// <param name="url">Url to retrieve the image.</param>
        /// <returns>Image from the url.</returns>
        public static Image DownloadImage(this string url)
        {
            return DownloadData(url).ToImage();
        }

        /// <summary>
        /// Converts a string to a HTML encoded string
        /// </summary>
        /// <param name="str">The string to convert to HTML</param>
        /// <returns>A HTML formatted string</returns>
        public static string HtmlEncode(this string str)
        {
            return HttpUtility.HtmlEncode(str);
        }

        /// <summary>
        /// Decodes a HTML encoded string
        /// </summary>
        /// <param name="str">The string to convert</param>
        /// <returns>A regualar string</returns>
        public static string HtmlDecode(this string str)
        {
            return HttpUtility.HtmlDecode(str);
        }

        /// <summary>
        /// A wrapper around HttpUtility.HtmlDecode.
        /// </summary>
        /// <param name="s">The string to be decoded.</param>
        /// <returns>The decode string.</returns>
        public static string HtmlSpecialEntitiesDecode(this string s)
        {
            return HttpUtility.HtmlDecode(s);
        }

        /// <summary>
        /// A wrapper around HttpUtility.HtmlEncode.
        /// </summary>
        /// <param name="s">The string to be encoded.</param>
        /// <returns>An encoded string.</returns>
        public static string HtmlSpecialEntitiesEncode(this string s)
        {
            return HttpUtility.HtmlEncode(s);
        }

        /// <summary>
        /// Converts new line(\n) and carriage return(\r) symbols to
        /// HTML line breaks.
        /// </summary>
        /// <param name="s">The string to convert.</param>
        /// <returns>The resulting string</returns>
        public static string NewLineToBreak(this string s)
        {
            Regex regEx = new Regex(@"[\n|\r]+");
            return regEx.Replace(s, "<br />");
        }

        /// <summary>
        /// Left pads the passed input using the HTML non-breaking string entity
        /// for the total number of spaces.
        /// </summary>
        /// <param name="s">The string to pad.</param>
        /// <param name="totalSpaces">The total number to pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadLeftHtmlSpaces(this string s, int totalSpaces)
        {
            string space = "&nbsp;";

            return s.PadLeft(space, totalSpaces * space.Length, false);
        }

        /// <summary>
        /// Right pads the passed input using the HTML non-breaking string entity
        /// for the total number of spaces.
        /// </summary>
        /// <param name="s">The string to pad.</param>
        /// <param name="length">The total length to pad the string.</param>
        /// <returns>A padded string.</returns>
        public static string PadRightHtmlSpaces(this string s, int length)
        {
            string space = "&nbsp;";

            return s.PadRight(space, length * space.Length, false);
        }

        /// <summary>
        /// Creates a list of all the links in an html document.
        /// </summary>
        /// <param name="html">HTML to parse.</param>
        /// <returns>A list of links.</returns>
        public static ArrayList ParseLinks(string html)
        {
            ArrayList list = new ArrayList();

            HtmlDocument doc = new HtmlDocument();

            doc.LoadHtml(html);

            foreach (HtmlNode img in doc.DocumentNode.SelectNodes("//a"))
            {
                list.Add(img.GetAttributeValue("href", null));
            }

            return list;
        }

        /// <summary>
        /// Creates a list of all the image urls in an html document.
        /// </summary>
        /// <param name="html">HTML to parse.</param>
        /// <returns>A list of image urls.</returns>
        public static ArrayList ParseImages(string html)
        {
            ArrayList list = new ArrayList();

            HtmlDocument doc = new HtmlDocument();  
      
            doc.LoadHtml(html);

            foreach (HtmlNode img in doc.DocumentNode.SelectNodes("//img"))
            {
                list.Add(img.GetAttributeValue("src", null));
            }

            return list;
        }

        /// <summary>
        /// Parses a query string into a NameValueCollection, using the encoding method using default encoding.
        /// </summary>
        /// <param name="str">The query string to parse.</param>
        /// <returns>A Name/Value collection.</returns>
        public static NameValueCollection ParseQueryString(this string str)
        {
            return HttpUtility.ParseQueryString(str, Encoding.UTF8);
        }

        /// <summary>
        /// Parses a query string into a NameValueCollection.
        /// Optionally allows the encoding to be specified.
        /// </summary>
        /// <param name="str">The query string to parse.</param>
        /// <param name="encoding">The encoding scheme to use when parsing the query string.</param>
        /// <returns>A Name/Value collection.</returns>
        public static NameValueCollection ParseQueryString(this string str, Encoding encoding)
        {
            return HttpUtility.ParseQueryString(str, encoding);
        }

        /// <summary>
        /// Converts all spaces to HTML non-breaking spaces.
        /// </summary>
        /// <param name="s">The string to convert.</param>
        /// <returns>The resulting string.</returns>
        public static string SpaceToNbsp(this string s)
        {
            string space = "&nbsp;";

            return s.Replace(" ", space);
        }

        /// <summary>
        /// Encodes a URL string, using the default encoding.
        /// </summary>
        /// <param name="str">The text to encode.</param>
        /// <returns>A URL encoded version of the source string.</returns>
        public static string UrlEncode(this string str)
        {
            return HttpUtility.UrlEncode(str, Encoding.UTF8);
        }

        /// <summary>
        /// URL encodes the specified string.
        /// Optionally allows the encoding to be specified.
        /// </summary>
        /// <param name="str">The text to encode.</param>
        /// <param name="encoding">The encoding scheme to use when URL encoding the string.</param>
        /// <returns>A URL encoded version of the source string.</returns>
        public static string UrlEncode(this string str, Encoding encoding)
        {
            return HttpUtility.UrlEncode(str, encoding);
        }

        /// <summary>
        /// Converts a string that has been encoded for transmission in a URL into a decoded string, 
        /// using the default encoding.
        /// </summary>
        /// <param name="str">The text to decode</param>
        /// <returns>A URL decoded version of the source string</returns>
        public static string UrlDecode(this string str)
        {
            return HttpUtility.UrlDecode(str, Encoding.UTF8);
        }

        /// <summary>
        /// Converts a string that has been encoded for transmission in a URL into a decoded string.
        /// Optionally allows the encoding to be specified.
        /// </summary>
        /// <param name="str">The text to decode</param>
        /// <param name="encoding">The encoding scheme to use when decoding the string</param>
        /// <returns>A URL decoded version of the source string</returns>
        public static string UrlDecode(this string str, Encoding encoding)
        {
            return HttpUtility.UrlDecode(str, encoding);
        }
    }
}
